/**
 * Author: luoqi
 * Created Date: 2025-11-12 21:40:1
 * Last Modified: 2025-11-13 01:40:36
 * Modified By: luoqi at <**@****>
 * Copyright (c) 2025 <*****>
 * Description:
 */

#include <usart.h>
#include <bsp.h>
#include <stdbool.h>
#include "utils/ringbuf.h"
#include "uart_port.h"

typedef struct {
    uint8_t rx_buf[UART_RX_BUFSZ];
    uint8_t tx_buf[UART_TX_BUFSZ];

    bool tx_finished;

    RingBuffer rb_tx;
    RingBuffer rb_rx;

    uint8_t rb_tx_buf[UART_TX_RB_BUFSZ];
    uint8_t rb_rx_buf[UART_RX_RB_BUFSZ];

    bool rx_lock;
} UartX;

static UartX uart1;

static void rb_rx1_lock(void)
{
    uart1.rx_lock = true;
}

static void rb_rx1_unlock(void)
{
    uart1.rx_lock = false;
}

static void task_uart_write(void)
{
    if(uart1.tx_finished) {
        int sz = rb_read(&uart1.rb_tx, uart1.tx_buf, sizeof(uart1.tx_buf));
        if(sz > 0) {
            uart1.tx_finished = false;
            HAL_UART_Transmit_DMA(&huart1, uart1.tx_buf, sz);
        }
    }
}

int uart_port_init(void)
{
    rb_init(&uart1.rb_tx, uart1.rb_tx_buf, sizeof(uart1.rb_tx_buf), NULL, NULL);
    rb_init(&uart1.rb_rx, uart1.rb_rx_buf, sizeof(uart1.rb_rx_buf), rb_rx1_lock, rb_rx1_unlock);
    task_add("uart1", task_uart_write, 1);
    uart1.tx_finished = true;
    HAL_UARTEx_ReceiveToIdle_DMA(&huart1, uart1.rx_buf, sizeof(uart1.rx_buf));
    return 0;
}

int uart_write(UartPort port, const void *data, size_t sz)
{
    size_t wsz = 0;
    switch(port) {
    case UART_PORT1:
        wsz = rb_write(&uart1.rb_tx, data, sz);
        break;
    default:
        return -1;
    }
    return wsz;
}

int uart_read(UartPort port, void *data, size_t sz)
{
    switch(port) {
    case UART_PORT1:
        if(uart1.rx_lock) {
            return 0;
        }
        return rb_read(&uart1.rb_rx, data, sz);
    default:
        return -1;
    }
}

int uart_transfer(UartPort port, const void *data, size_t sz, size_t timeout)
{
    int ret = HAL_UART_Transmit(&huart1, (uint8_t *)data, (uint16_t)sz, (uint32_t)timeout);
    if(ret != HAL_OK) {
        return -ret;
    }
    return ret;
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if(huart->Instance == USART1) {
        rb_write(&uart1.rb_rx, uart1.rx_buf, Size);
    }
    HAL_UARTEx_ReceiveToIdle_DMA(&huart1, uart1.rx_buf, sizeof(uart1.rx_buf));
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1) {
        uart1.tx_finished = true;
    }
}

void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1) {
        
    }
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_ORE) != RESET) {
        __HAL_UART_CLEAR_OREFLAG(huart);
    }
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_IDLE) != RESET) {
        __HAL_UART_CLEAR_IDLEFLAG(huart);
    }
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_FE) != RESET) {
        __HAL_UART_CLEAR_FEFLAG(huart);
    }
    if(__HAL_UART_GET_FLAG(huart, UART_FLAG_NE) != RESET) {
        __HAL_UART_CLEAR_NEFLAG(huart);
    }
}
